package myapp

import (
	"fmt"
	"sync"
)

// Add 函数将两个整数相加
func Add(a, b int) int {
	return a + b
}

// Subtract 函数将两个整数相减
func Subtract(a, b int) int {
	return a - b
}

func Divide(a, b int) (float64, error) {
	if b == 0 {
		return 0, fmt.Errorf("cannot divide by zero")
	}
	return float64(a / b), nil
}

// 计算斐波那契数列
func Fibonacci(n int) int {
	if n <= 1 {
		return n
	}
	return Fibonacci(n-1) + Fibonacci(n-2)
}

// 并行计算斐波那契数列
func ParallelFibonacci(n int) int {
	if n <= 1 {
		return n
	}

	var wg sync.WaitGroup
	wg.Add(2)

	var result1, result2 int

	go func() {
		defer wg.Done()
		result1 = Fibonacci(n - 1)
	}()

	go func() {
		defer wg.Done()
		result2 = Fibonacci(n - 2)
	}()

	wg.Wait()
	return result1 + result2
}

func ParallelFibonacciWithChannel(n int) int {
	var fib func(n int) <-chan int
	fib = func(n int) <-chan int {
		result := make(chan int)
		go func() {
			defer close(result)
			if n <= 2 {
				result <- 1
				return
			}

			result <- <-fib(n-1) + <-fib(n-2)
		}()
		return result
	}
	return <-fib(n)
}

// 优化版本：使用缓存和更好的并发控制
func ParallelFibonacciWithCache(n int) int {
	if n <= 2 {
		return 1
	}

	// 使用缓存避免重复计算
	cache := &sync.Map{}

	// 使用工作池模式而不是无限制的递归
	return fibonacciWithCache(n, cache)
}

func fibonacciWithCache(n int, cache *sync.Map) int {
	if n <= 2 {
		return 1
	}

	// 检查缓存
	if val, ok := cache.Load(n); ok {
		return val.(int)
	}

	// 使用channel和goroutine计算
	ch1 := make(chan int, 1)
	ch2 := make(chan int, 1)

	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		defer wg.Done()
		ch1 <- fibonacciWithCache(n-1, cache)
	}()

	go func() {
		defer wg.Done()
		ch2 <- fibonacciWithCache(n-2, cache)
	}()

	wg.Wait()

	result1 := <-ch1
	result2 := <-ch2
	result := result1 + result2

	cache.Store(n, result)
	return result
}

func ParallelFibonacciDP(n int) int {
	if n <= 2 {
		return 1
	}

	// 使用slice存储已计算的值
	dp := make([]int, n+1)
	dp[1] = 1
	dp[2] = 1

	// 使用worker pool
	const maxWorkers = 4
	sem := make(chan struct{}, maxWorkers)

	var wg sync.WaitGroup
	var mu sync.Mutex

	for i := 3; i <= n; i++ {
		wg.Add(1)
		go func(idx int) {
			defer wg.Done()
			sem <- struct{}{}
			defer func() { <-sem }()

			mu.Lock()
			if dp[idx] == 0 { // 避免重复计算
				dp[idx] = dp[idx-1] + dp[idx-2]
			}
			mu.Unlock()
		}(i)
	}

	wg.Wait()
	return dp[n]
}
